﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;

namespace LaughingDog.Input
{
    /// <summary>
    /// Enumeration of all Keyboard key event states.
    /// </summary>
    public enum KeyboardKeyStates { Released, JustReleased, Pressed, JustPressed }

    public class Keyboard : InputDevice
    {
        private KeyboardState mCurrentState = new KeyboardState();
        private KeyboardState mPreviousState = new KeyboardState();
        private Dictionary<Keys, KeyboardKeyStates> mKeyStates = new Dictionary<Keys, KeyboardKeyStates>();
        private List<Keys> mPressedKeys = new List<Keys>();

        /// <summary>
        /// Creates a new instance of a Keyboard device. One is automatically created in the InputManager and can be accessed via InputManager.Instance.Keyboard.
        /// </summary>
        public Keyboard()
        {
            foreach (Keys key in Enum.GetValues(typeof(Keys)))
                mKeyStates.Add(key, KeyboardKeyStates.Released);
        }

        /// <summary>
        /// Updates this Keyboard device.
        /// </summary>
        public override void Update()
        {
            mPressedKeys.Clear();

            mCurrentState = Microsoft.Xna.Framework.Input.Keyboard.GetState();

            foreach(Keys key in Enum.GetValues(typeof(Keys)))
            {                
                if (mCurrentState.IsKeyDown(key)
                && mPreviousState.IsKeyUp(key)) // Down this frame, not the last
                {
                    mKeyStates[key] = KeyboardKeyStates.JustPressed;
                    mPressedKeys.Add(key);
                }
                else if (mCurrentState.IsKeyDown(key)
                && mPreviousState.IsKeyDown(key)) // Down this frame and the last
                {
                    mKeyStates[key] = KeyboardKeyStates.Pressed;
                }
                else if (mCurrentState.IsKeyUp(key)
                    && mPreviousState.IsKeyDown(key)) // Up this frame, not the last
                {
                    mKeyStates[key] = KeyboardKeyStates.JustReleased;
                }
                else if (mCurrentState.IsKeyUp(key)
                    && mPreviousState.IsKeyUp(key)) // Up this frame and the last
                {
                    mKeyStates[key] = KeyboardKeyStates.Released;
                }
            }

            mPreviousState = mCurrentState;

            base.Update();
        }

        /// <summary>
        /// Returns whether a keyboard key is currently pressed. Down last frame and this one.
        /// </summary>
        /// <param name="key">The mouse key to check.</param>
        /// <returns>True if the key is currenty pressed, false if not.</returns>
        public Boolean KeyPressed(Keys key)
        {
            return IsKeyInState(key, KeyboardKeyStates.Pressed);
        }

        /// <summary>
        /// Returns whether a keyboard key has just been pressed. Down this frame but up during last one.
        /// </summary>
        /// <param name="key">The mouse key to check.</param>
        /// <returns>True if the key was just pressed, false if not.</returns>
        public Boolean KeyJustPressed(Keys key)
        {
            return IsKeyInState(key, KeyboardKeyStates.JustPressed);
        }

        /// <summary>
        /// Returns whether a keyboard key has just been released. Up this frame but down during last one.
        /// </summary>
        /// <param name="key">The keyboard key to check.</param>
        /// <returns>True if the key was just released, false if not.</returns>
        public Boolean KeyJustReleased(Keys key)
        {
            return IsKeyInState(key, KeyboardKeyStates.JustReleased);
        }

        /// <summary>
        /// Returns whether a keyboard key is currently released. Up last frame and this one.
        /// </summary>
        /// <param name="key">The keyboard key to check.</param>
        /// <returns>True if the key is currently released, false if not.</returns>
        public Boolean KeyReleased(Keys key)
        {
            return IsKeyInState(key, KeyboardKeyStates.Released);
        }

        /// <summary>
        /// Checks if a keyboard key is in a certain state.
        /// </summary>
        /// <param name="key">The keyboard key to check.</param>
        /// <param name="state">The state to check.</param>
        /// <returns>True if the key is in the specified state, false if not.</returns>
        public Boolean IsKeyInState(Keys key, KeyboardKeyStates state)
        {
            return mKeyStates[key] == state;
        }

        /// <summary>
        /// Gets the state of a certain key.
        /// </summary>
        /// <param name="key">The key to check.</param>
        /// <returns>The state the key is in.</returns>
        public KeyboardKeyStates GetKeyState(Keys key)
        {
            return mKeyStates[key];
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public String GetStringTyped()
        {
            String typedString = "";

            for (int i = 0; i < mPressedKeys.Count; i++)
			{
                if (mPressedKeys[i] == Keys.Space)
                    typedString += " ";
                else
                {
                    if (mPressedKeys[i].ToString().Length == 1)                    
                        typedString += mPressedKeys[i].ToString();                                                
                }
			}  

            return typedString;
        }
    }
}
